/*
 * Bastation.cc
 *
 *  Created on: Sep 22, 2012
 *      Author: HUNG
 */

#include "Bastation.h"
#include "Target.h"
#include "string.h"

Define_Module(Bastation);

void Bastation::initialize()
{
    this->numberNodes   = (int)this->par("numNodes");
    this->xpos          = par("xpos");
    this->ypos          = par("ypos");
    this->trRange       = par("trRange");
    this->frameNumber   = par("frameNumber");
    this->numPos        = 0;
    this->X_MAX         = getParentModule()->par("X_MAX");
    this->Y_MAX         = getParentModule()->par("Y_MAX");
    this->typeProtocol  = getParentModule()->par("typeProtocol");
    this->typeEstimate  = getParentModule()->par("typeEstimate");
    this->t_end_to_end = 0;
    this->timeStep      = getParentModule()->par("TimeStep");

    if(typeProtocol == 0 && typeEstimate == 0)
    {
        remove("data/Output-L-ARPEES.txt");
        remove("data/Energy-L.txt");
    }
    else if(typeProtocol == 1 && typeEstimate == 0)
    {
        remove("data/Output-L-EMRP.txt");
        remove("data/Energy-L.txt");
    }
    else if(typeProtocol == 0 && typeEstimate == 1)
    {
        remove("data/Output-EKF-ARPEES.txt");
        remove("data/Energy-EKF.txt");
    }
    else if(typeProtocol == 1 && typeEstimate == 1)
    {
        remove("data/Output-EKF-EMRP.txt");
        remove("data/Energy-EKF.txt");
    }

    this->countNoise = 0;
    if((int)getParentModule()->par("useFile") == 0) remove("data/Noise.txt");
    else
    {
        FILE *f = fopen("data/Noise.txt", "r");
        if(f != NULL)
        {
            int index = 0;
            while(!feof(f))
            {
                fscanf(f,"%lf\n", &noise[index]);
                index++;
            }
        }
    }

    cMessage *msg = new cMessage();
    msg->setKind(SMSG_INIT);
    scheduleAt(simTime(), msg);
}

void Bastation::handleMessage(cMessage *msg)
{
    if(msg->isSelfMessage())
    {
        if(msg->getKind() == SMSG_INIT)
        {
            initLinks();
            delete msg;
        }

    }
    else
    {
        if(msg->getKind() == DataToBSMsg)
        {
            Sensor *s = (Sensor *)simulation.getModule(((DataToBS *)msg)->getSrcAddress());
            if(!s->isClusterHead) s->setDisplay("");
            char bubble[20];
            sprintf(bubble, "BS received data frame %d !", (int)par("frameNumber") - this->frameNumber + 1);
            //this->bubble(bubble);
            if(!testAlive())
            {
                endSimulation();
            }
            else
            {
                this->frameNumber--;
                Target *tar1 = (Target *)simulation.getModule(2);
                if(this->frameNumber == 0)
                {
                    t_end_to_end = simTime();

                    double Te2e = t_end_to_end.dbl() - t_start.dbl();

                    ev <<"\n -----------Finish time step-----------------------";
                    ev <<"\n End to End Delay = " << simTime() - t_start;
                    //Save data
                    this->frameNumber = par("frameNumber");
                    double xm = ((DataToBS *)msg)->getX();
                    double ym = ((DataToBS *)msg)->getY();

                    ev <<"\n Meas = " << xm <<"\t\t" << ym;
                    ev <<"\n True = " << tar1->xpos <<"\t\t" << tar1->ypos;
                    ev <<"\n -------------------------------------------------\n";

                    const char *filePath;
                    if(typeProtocol == 0 && typeEstimate == 0)
                    {
                        filePath = "data/Output-L-ARPEES.txt";
                    }
                    else if(typeProtocol == 1 && typeEstimate == 0)
                    {
                        filePath = "data/Output-L-EMRP.txt";
                    }
                    else if(typeProtocol == 0 && typeEstimate == 1)
                    {
                        filePath = "data/Output-EKF-ARPEES.txt";
                    }
                    else if(typeProtocol == 1 && typeEstimate == 1)
                    {
                        filePath = "data/Output-EKF-EMRP.txt";
                    }
                    double totalEnergy = 0;
                    Sensor *s;
                    for(int i = NUMTARGET + 2; i < simulation.getLastModuleId(); i++)
                    {
                        s = (Sensor *)simulation.getModule(i);
                        totalEnergy += s->energy;
                    }

                    double dError = distance(tar1->xpos, tar1->ypos, xm, ym);

                    FILE *file = fopen(filePath, "a");
                    fprintf(file,"%f    %f  %f  %f  %f  %f  %f\n", tar1->xpos, tar1->ypos, xm, ym, Te2e, totalEnergy / numberNodes, dError);
                    fclose(file);
                    this->numPos++;
                }
                else
                {
                    Sensor *s;
                    for(int i = 0; i < tar1->total; i++)
                    {
                        s = tar1->cluster[i];
                        if(s->isClusterHead)
                        {
                            if(!s->isDead)
                            {
                                s->sendSeflMsgToCH();
                                break;
                            }
                            else
                            {
                                this->frameNumber = par("frameNumber");
                            }
                        }
                    }

                }
            }

            delete msg;
        }
    }
}

void Bastation::finish()
{
    Sensor *s;
    const char *fileName;
    if(typeEstimate == 0)
    {
        if(typeProtocol == 0) fileName = "data/Energy-L.txt";
        else fileName = "data/Energy-L-EMRP.txt";
    }
    else fileName = "data/Energy-EKF.txt";
    for(int i = NUMTARGET + 2; i < simulation.getLastModuleId(); i++)
    {
        s = (Sensor *)simulation.getModule(i);
        this->storeValue(s->xpos, s->ypos, s->energy, fileName);
    }
}

//create links between BS and sensors within its transmission range
void Bastation::initLinks()
{
    cModule *mod;
    trRange = par("trRange");

    //duyet tat ca cac nut sensor
    for(int i = NUMTARGET + 2; i < simulation.getLastModuleId(); i++)
    {
        int x, y;
        mod = (cModule *)simulation.getModule(i);
        if(this->getId() != mod->getId())
        {
            x = (double)((Sensor *)mod)->xpos;
            y = (double)((Sensor *)mod)->ypos;
            double xlength = (double)(x - this->xpos);
            double ylength = (double)(y - this->ypos);
            double distance = sqrt(xlength * xlength + ylength * ylength);
            if(distance <= (double)this->trRange)
            {
                char idStr[2];
                sprintf(idStr, "%d to %d", this->getId(), i);
                char gateName[5] = "link";
                char *temp = strcat(gateName, idStr);
                cGate *ownGate = addGate(temp, cGate::OUTPUT);
                cGate * otherGate = mod->addGate(temp, cGate::INPUT);
                ownGate->connectTo(otherGate);
                ownGate->getDisplayString().setTagArg("ls", 0, "blue");
                ownGate->getDisplayString().setTagArg("ls", 2, "d");

                char *outName = new char[15];
                char *inName = new char[15];
                sprintf(outName, "O_%d", this->getId());
                sprintf(inName, "I_%d", mod->getId());
                ownGate = mod->addGate(outName, cGate::OUTPUT);
                otherGate = addGate(inName, cGate::INPUT);
                ownGate->connectTo(otherGate);
                ownGate->getDisplayString().setTagArg("ls", 1, "0");
                ownGate->getDisplayString().setTagArg("ls", 2, "d");
            }
        }
    }
}


/**
 * Distance between Bastation and module has pos (x, y)
 */
double Bastation::distanceCal(double x, double y)
{
    double xlength = this->xpos - x;
    double ylength = this->ypos - y;
    double distance = sqrt(xlength * xlength + ylength * ylength);
    return distance;
}

/**
 * Check Alive of nodes around BS
 */
bool Bastation::testAlive()
{
    Enter_Method_Silent("testAlive()");
    bool alive = false;
    Sensor *s;
    int count = 0;
    for(cModule::GateIterator i(this); !i.end(); i++)
    {
        cGate *gate = i();
        if(gate->getType() == cGate::OUTPUT)
        {
            cGate *otherGate = gate->getPathEndGate();
            s = (Sensor *)otherGate->getOwnerModule();
            if(!s->isDead)
            {
                alive = true;
                count++;
                if(count > 3) break;
            }
        }
    }
    if(count <= 3) alive = false;
    return alive;
}

void Bastation::storeValue(double value, const char *fileName)
{
    FILE *f = fopen(fileName, "a");
    fprintf(f, "%f\n", value);
    fclose(f);
}

void Bastation::storeValue(double value1, double value2, double value3, const char *fileName)
{
    FILE *f = fopen(fileName, "a");
    fprintf(f, "%f %f %f\n", value1, value2, value3);
    fclose(f);
}

double Bastation::createNoise()
{
    double temp = noise[countNoise];
    countNoise++;
    return temp;
}


